package org.phantom.securityframework.auth;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.config.Ini;
import org.apache.shiro.config.Ini.Section;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.phantom.securityframework.api.Permission;
import org.phantom.securityframework.api.Resource;
import org.phantom.securityframework.api.SecurityManager;
import org.phantom.securityframework.api.ShiroConfigAware;
import org.phantom.securityframework.api.factory.ManagerFactory;
import org.phantom.securityframework.api.util.AuthUtil;
import org.phantom.securityframework.auth.realm.ResourceRealm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 基于Shiro的认证/鉴权平台资源初始化Filter
 * @author david
 *
 */
public abstract class DefaultHttpAuthInitFilter extends AbstractShiroFilter {


	private static final Logger logger = LoggerFactory.getLogger(DefaultHttpAuthInitFilter.class);

    public static final String CONFIG_INIT_REALMS = "realms";

    
    
    private Ini ini;
    
    @Override
    public void init() throws Exception {
        configure();
    }
    
    /**
     * 存储Filters、realms等实现类的ClassLoader。
     * 如果在OSGI环境下重写securityframework默认实现，覆盖该方法，添加自定义实现的ClassLoader
     * @param loaders
     * @return
     */
    protected Map<String, ClassLoader> buildRealmClassLoaders(Map<String, ClassLoader> loaders){
		loaders.put("authc", org.apache.shiro.web.filter.authc.UserFilter.class.getClassLoader());
		loaders.put("factory", ManagerFactory.class.getClassLoader());
		return loaders;
    }
    
    /**
     * 加载当前环境的Shiro配置
     * @throws Exception
     */
    protected void configure() throws Exception {
		
    	
        this.ini = loadIniFromConfig();
        
        if (CollectionUtils.isEmpty(ini)) {
        	throw new Exception("Null or empty configuration specified via 'config' init-param.  " +
                    "Checking path-based configuration.");
        }
        
        /*
         *	从DB获取ini中的urls数据，并设置到ini.sections属性
         *  如果没有使用DB的方式，此操作可以忽视
         */
        
        IniSecurityManagerFactory securityManagerFactory = this.getSecurityManagerFactory(ini);
        DefaultSecurityManager securityManager = this.getSecurityManager(securityManagerFactory);
        ManagerFactory factory = null;
        if(securityManager instanceof SecurityManager){
        	factory = ((SecurityManager)securityManager).getManagerFactory(ini);
        }
        Map<String, String> perms = loadResources(factory);
        Section section = ini.addSection("urls");
        section.putAll(perms);
        
        /* 打印ini配置信息 */
        Collection<Section> c_sections = ini.getSections();
        for(Iterator<Section> i= c_sections.iterator(); i.hasNext();) {
        	
        	Section s = (Section)i.next();
        	logger.info("[" + s.toString() + "]");
        	
        	Set<Entry<String, String>> set = s.entrySet();
        	
            for (Iterator<Map.Entry<String, String>> it = set.iterator(); it.hasNext();) {
                Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
                logger.info(entry.getKey() + " = " + entry.getValue());
            }
        }

        applySecurityManager(securityManager,ini);
        applyFilterChainResolver(ini, securityManagerFactory.getBeans());
    }

    
    /**
     * 加载当前环境需要保护的所有资源,并注入到Shiro中
     * @return
     */
    private Map<String, String> loadResources(ManagerFactory managerFactory) {
    	List<Resource> resList = this.getAllResource(managerFactory);
    	Map<String, String> resultMap = convertForIni(resList);
    	return resultMap;
    	
    }
    
    
    private List<Resource> getAllResource(ManagerFactory factory){
    	String platform = ini.getSectionProperty("platform", "platform");
    	String subsystem = ini.getSectionProperty("platform", "subsystem");
    	if(platform==null || "".equals(platform)){
    		throw new ConfigurationException("platform unknow!");
    	}
    	AuthUtil.setPlatformId(platform);
		try {
			ResourceRealm realm = this.buildResourceRealm(factory);
			List<Resource> resList = realm.loadSubsystemPermission(platform, subsystem);
			return resList;
		} catch (Exception e) {
			logger.error(String.format("加载平台[%s]子系统[%s]ini-urls数据失败!原因:[%s]",platform,subsystem,e.getMessage()), e);
		}
		return null;
    }

    /** 
     * 将操作权限List转换成Ini对象使用的Map
     */
    protected Map<String, String> convertForIni(List<Resource> resList) {
    	Map<String, String> map = null;
    	
    	
    	try {
			if(resList!=null){
				map = new HashMap<String, String>();
				for (Resource resource : resList) {
					StringBuilder value = new StringBuilder();
					if(resource.getResType().contains("authc")){
						value.append("authc");
						List<Permission> perm = resource.getPermissions();
						value.append(",perms[");
						for (Permission permission : perm) {
							value.append(permission.getPermissionName()).append(",");
						}
						value = new StringBuilder(value.substring(0,value.length()-1));
						value.append("]");
					}
//					if(resource.getResType().contains("rest")){
//						value.append(",rest[").append(resource.getRequestMethod()).append("]");
//					}
					map.put(resource.getRes(), value.toString());
				}
			}
		} catch (Exception e) {
			logger.error("url数据构造出错", e);
		}
    	
//    	
//    	try {
//    		if(permList != null) {
//    			map = new HashMap<String, String>();
//	    		for(int i=0; i<permList.size(); i++) {
//	    			org.phantom.securityframework.api.Permission perm = (Permission) permList.get(i);
//	    			String permID = perm.getPermissionName();
//	    			List<org.phantom.securityframework.api.Resource> resList = perm.getResources();
//	    			if(resList != null) {
//	    	    		for(int j=0; j<resList.size(); j++) {
//	    	    			Resource res = (Resource) resList.get(j);
//	    	    			String resName = (String) res.getRes();
//	    	    			String resType = res.getResType();
//	    	    			String value = "authc";
//	    	    			if("authc".equals(perm.getAuthType())) {
//	    	    				value = value + ", perms[" + permID + "],rest["+resType+"]";
//	    	    			}
//	    	    			if(resName==null || value==null) {
//	    	    				throw new Exception("resName or value is null in ini configs. resName=" + resName + ", value=" + value);
//	    	    			} else {
//	    	    				map.put(resName, value);
//	    	    			}
//	    	    		}
//	        		}
//	    		}
//    		}
//    	} catch(Exception e) {
//    		logger.error("操作权限List转换Ini对象失败!", e);
//    	}
		return map;
    }
    
    protected Ini loadIniFromConfig() {
        Ini ini = null;
        String config = this.getShiroConfig();
        if (config != null) {
            ini = new Ini();
            ini.load(config);
            return ini;
        }
        return null;
    }
    /**
     * 创建SecurityManager，基于Ini配置构建Realm,Filter等
     * @param ini
     * @return
     */
	protected void applySecurityManager(DefaultSecurityManager securityManager,Ini ini) {

        /*
    	 * 当mode=native时
    	 * 		securityManager获取的SessionManager类型为DefaultWebSessionManager
    	 * 		sessionManager具备setSessionDAO方法，可指定session存放介质
    	 * 当mode=http时
    	 * 		securityManager获取的SessionManager类型为ServletContainerSessionManager
    	 * 		不具备setSessionDAO方法，不能指定session存放介质
    	 * 
    	 * 默认为http
    	 */
//    	String mode = securityManager.getSessionMode();
//    	if("native".equals(mode)) {
//    		SessionManager sessionManager = this.getSessionManager();
//    		if(sessionManager != null)
//    			securityManager.setSessionManager(sessionManager);
//    	}
    	
    	securityManager.setRememberMeManager(null);
        setSecurityManager((DefaultWebSecurityManager) securityManager);
        SecurityUtils.setSecurityManager(securityManager);
    }

    /**
     * 基于Ini创建FilterChain
     * @param ini
     * @param defaults
     */
    protected void applyFilterChainResolver(Ini ini, Map<String, ?> defaults) {
        if (ini == null || ini.isEmpty()) {
            return;
        }
        //only create a resolver if the 'filters' or 'urls' sections are defined:
        Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS);
        Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS);
        if ((urls != null && !urls.isEmpty()) || (filters != null && !filters.isEmpty())) {
            //either the urls section or the filters section was defined.  Go ahead and create the resolver
            //and set it:
            IniFilterChainResolverFactory filterChainResolverFactory = new IniFilterChainResolverFactory(ini, defaults);
            filterChainResolverFactory.setFilterConfig(getFilterConfig());
            
            ClassLoader old = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(UserFilter.class.getClassLoader());
            FilterChainResolver resolver = filterChainResolverFactory.getInstance();
            Thread.currentThread().setContextClassLoader(old);
            
            for (String s : defaults.keySet()) {
            	Object bean = defaults.get(s);
				if(bean instanceof ShiroConfigAware){
					ShiroConfigAware o = (ShiroConfigAware) bean;
					o.setConfig(this.ini);
				}
			}
            
            setFilterChainResolver(resolver);
        }
    }
    
    /**
     * 创建IniSecurityManagerFactory
     * @param ini
     * @return
     */
    protected abstract IniSecurityManagerFactory getSecurityManagerFactory(Ini ini);
    /**
     * 获取当前环境的Shiro Ini配置
     * @return
     */
    protected abstract String getShiroConfig();
    /**
     * 获取当前环境的SecurityManager
     * @param factory
     * @return
     */
    protected abstract DefaultSecurityManager getSecurityManager(IniSecurityManagerFactory factory);
    
    /**
     * 创建SessionManager
     * @return
     */
    protected SessionManager getSessionManager(){
    	return new DefaultSessionManager();
    }
    
//    /**
//     * 获取当前环境的PermissionRealm
//     * @return
//     */
//    protected PermissionRealm buildPermissionRealm(ManagerFactory factory) throws Exception{
//        PermissionRealm manager = (PermissionRealm)factory.getService(PermissionRealm.class);
//		return manager;
//    }
    
    protected ResourceRealm buildResourceRealm(ManagerFactory factory)throws Exception{
    	return (ResourceRealm) factory.getService(ResourceRealm.class);
    }


}
